/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.diet263.view;

import java.io.IOException;
import java.lang.reflect.Method;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiManager;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.diet263.nfcleedemo.R;
import com.diet263.utils.NFCUtils;

public class WriteWifiConfigToNfcDialog extends AlertDialog implements TextWatcher, View.OnClickListener,
		CompoundButton.OnCheckedChangeListener {

	private static final String NFC_TOKEN_MIME_TYPE = "application/vnd.wfa.wsc";

	private static final String TAG = WriteWifiConfigToNfcDialog.class.getName().toString();
	private static final String PASSWORD_FORMAT = "102700%s%s";
	private static final int HEX_RADIX = 16;
	private static final char[] hexArray = "0123456789ABCDEF".toCharArray();

	private final PowerManager.WakeLock mWakeLock;

	// private AccessPoint mAccessPoint;

	private int security;
	private int networkId = -1;
	private View mView;
	private Button mSubmitButton;
	private Button mCancelButton;
	private Handler mOnTextChangedHandler;
	private TextView mPasswordView;
	private TextView mLabelView;
	private CheckBox mPasswordCheckBox;
	private ProgressBar mProgressBar;
	private WifiManager mWifiManager;
	private String mWpsNfcConfigurationToken;
	private Context mContext;

	public WriteWifiConfigToNfcDialog(Context context, /*
														 * AccessPoint
														 * accessPoint,
														 */WifiConfiguration config, WifiManager wifiManager) {
		super(context);

		mContext = context;
		String stringTag = "WriteWifiConfigToNfcDialog:wakeLock";
		mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
				PowerManager.PARTIAL_WAKE_LOCK, stringTag);
		// mAccessPoint = accessPoint;
		networkId = config.networkId;
		security = getSecurity(config);
		mOnTextChangedHandler = new Handler();
		mWifiManager = wifiManager;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		mView = getLayoutInflater().inflate(R.layout.write_wifi_config_to_nfc, null);

		setView(mView);
		setInverseBackgroundForced(true);
		setTitle(R.string.setup_wifi_nfc_tag);
		setCancelable(true);
		setButton(DialogInterface.BUTTON_NEUTRAL, mContext.getResources().getString(R.string.write_tag),
				(OnClickListener) null);
		setButton(DialogInterface.BUTTON_NEGATIVE, mContext.getResources().getString(R.string.cancel),
				(OnClickListener) null);

		mPasswordView = (TextView) mView.findViewById(R.id.password);
		mLabelView = (TextView) mView.findViewById(R.id.password_label);
		mPasswordView.addTextChangedListener(this);
		mPasswordCheckBox = (CheckBox) mView.findViewById(R.id.show_password);
		mPasswordCheckBox.setOnCheckedChangeListener(this);
		mProgressBar = (ProgressBar) mView.findViewById(R.id.progress_bar);

		super.onCreate(savedInstanceState);

		mSubmitButton = getButton(DialogInterface.BUTTON_NEUTRAL);
		mSubmitButton.setOnClickListener(this);
		mSubmitButton.setEnabled(false);

		mCancelButton = getButton(DialogInterface.BUTTON_NEGATIVE);
	}

	@Override
	public void onClick(View v) {
		// mWakeLock.acquire();

		String password = mPasswordView.getText().toString();
		/*
		 * String wpsNfcConfigurationToken =
		 * mWifiManager.getWpsNfcConfigurationToken(mAccessPoint.networkId);
		 */

		// String wpsNfcConfigurationToken =
		// mWifiManager.getWpsNfcConfigurationToken(mConfig.networkId);
		String wpsNfcConfigurationToken = "";
		try {
			Class<? extends WifiManager> clazz = mWifiManager.getClass();
			Method getStrMethod = clazz.getDeclaredMethod("getWpsNfcConfigurationToken", int.class);
			getStrMethod.setAccessible(true);
			wpsNfcConfigurationToken = (String) getStrMethod.invoke(mWifiManager, networkId);
		} catch (Exception e) {
			e.printStackTrace();
		}
		String passwordHex = byteArrayToHexString(password.getBytes());

		String passwordLength = password.length() >= HEX_RADIX ? Integer.toString(password.length(), HEX_RADIX) : "0"
				+ Character.forDigit(password.length(), HEX_RADIX);

		passwordHex = String.format(PASSWORD_FORMAT, passwordLength, passwordHex).toUpperCase();

		if (wpsNfcConfigurationToken.contains(passwordHex)) {
			mWpsNfcConfigurationToken = wpsNfcConfigurationToken;
			Log.e(TAG, "mWpsNfcConfigurationToken = " + mWpsNfcConfigurationToken);
			Activity activity = getOwnerActivity();
			NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(activity);

			nfcAdapter.enableReaderMode(activity, new NfcAdapter.ReaderCallback() {
				@Override
				public void onTagDiscovered(Tag tag) {
					handleWriteNfcEvent(tag);
				}
			}, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_NFC_B | NfcAdapter.FLAG_READER_NFC_BARCODE
					| NfcAdapter.FLAG_READER_NFC_F | NfcAdapter.FLAG_READER_NFC_V, null);

			mPasswordView.setVisibility(View.GONE);
			mPasswordCheckBox.setVisibility(View.GONE);
			mSubmitButton.setVisibility(View.GONE);
			InputMethodManager imm = (InputMethodManager) getOwnerActivity().getSystemService(
					Context.INPUT_METHOD_SERVICE);
			imm.hideSoftInputFromWindow(mPasswordView.getWindowToken(), 0);

			mLabelView.setText(R.string.status_awaiting_tap);

			mView.findViewById(R.id.password_layout).setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
			mProgressBar.setVisibility(View.VISIBLE);
		} else {
			mLabelView.setText(R.string.status_invalid_password);
		}
	}

	private void handleWriteNfcEvent(Tag tag) {
		Ndef ndef = Ndef.get(tag);

		if (ndef != null) {
			if (ndef.isWritable()) {
				NdefRecord record = NdefRecord.createMime(NFC_TOKEN_MIME_TYPE,
						hexStringToByteArray(mWpsNfcConfigurationToken));
				try {
					ndef.connect();
					ndef.writeNdefMessage(new NdefMessage(record));
					getOwnerActivity().runOnUiThread(new Runnable() {
						@Override
						public void run() {
							mProgressBar.setVisibility(View.GONE);
						}
					});
					setViewText(mLabelView, R.string.status_write_success);
					setViewText(mCancelButton, R.string.cancel);
				} catch (IOException e) {
					setViewText(mLabelView, R.string.status_failed_to_write);
					Log.e(TAG, "Unable to write Wi-Fi config to NFC tag.", e);
					return;
				} catch (FormatException e) {
					setViewText(mLabelView, R.string.status_failed_to_write);
					Log.e(TAG, "Unable to write Wi-Fi config to NFC tag.", e);
					return;
				}
			} else {
				setViewText(mLabelView, R.string.status_tag_not_writable);
				Log.e(TAG, "Tag is not writable");
			}
		} else {
			setViewText(mLabelView, R.string.status_tag_not_writable);
			Log.e(TAG, "Tag does not support NDEF");
		}
	}

	@Override
	public void dismiss() {
		// if (mWakeLock.isHeld()) {
		// mWakeLock.release();
		// }

		super.dismiss();
	}

	@Override
	public void onTextChanged(CharSequence s, int start, int before, int count) {
		mOnTextChangedHandler.post(new Runnable() {
			@Override
			public void run() {
				enableSubmitIfAppropriate();
			}
		});
	}

	private void enableSubmitIfAppropriate() {

		if (mPasswordView != null) {
			if (security == NFCUtils.SECURITY_WEP) {
				mSubmitButton.setEnabled(mPasswordView.length() > 0);
			} else if (security == NFCUtils.SECURITY_PSK) {
				mSubmitButton.setEnabled(mPasswordView.length() >= 8);
			}
		} else {
			mSubmitButton.setEnabled(false);
		}

	}

	private void setViewText(final TextView view, final int resid) {
		getOwnerActivity().runOnUiThread(new Runnable() {
			@Override
			public void run() {
				view.setText(resid);
			}
		});
	}

	@Override
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
		mPasswordView
				.setInputType(InputType.TYPE_CLASS_TEXT
						| (isChecked ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
								: InputType.TYPE_TEXT_VARIATION_PASSWORD));
	}

	private static byte[] hexStringToByteArray(String s) {
		int len = s.length();
		byte[] data = new byte[len / 2];

		for (int i = 0; i < len; i += 2) {
			data[i / 2] = (byte) ((Character.digit(s.charAt(i), HEX_RADIX) << 4) + Character.digit(s.charAt(i + 1),
					HEX_RADIX));
		}

		return data;
	}

	private static String byteArrayToHexString(byte[] bytes) {
		char[] hexChars = new char[bytes.length * 2];
		for (int j = 0; j < bytes.length; j++) {
			int v = bytes[j] & 0xFF;
			hexChars[j * 2] = hexArray[v >>> 4];
			hexChars[j * 2 + 1] = hexArray[v & 0x0F];
		}
		return new String(hexChars);
	}

	@Override
	public void beforeTextChanged(CharSequence s, int start, int count, int after) {
	}

	@Override
	public void afterTextChanged(Editable s) {
	}

	public int getSecurity(WifiConfiguration config) {
		if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
			return NFCUtils.SECURITY_PSK;
		}
		if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) || config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
			return NFCUtils.SECURITY_EAP;
		}
		return (config.wepKeys[0] != null) ? NFCUtils.SECURITY_WEP : NFCUtils.SECURITY_NONE;
	}
}
